#pragma once
#include "tContainer_t.h"
#include <vector>
#include <iostream>
#include <sstream>

using namespace std;

// this is a global flag to indicate if the user wants to quit
int QUIT_ENTERED	=	 0;

// container id var. and const values
int C_TYPE			=	 0;
const int C_LIST	=	 1;
const int C_VECTOR	=	 2;

void printContainerSelection(){

	cout << "Choose what type of container to use:" << endl;
	cout << "1. std::vector<std::string*>" << endl;
	cout << "2. std::list<std::string*>" << endl;
	cout << ":";

}

void printOperationSelection() {
	
	cout << "Choose an operation on the container (or quit):" << endl;
	cout << "0. []\t" << "get element by operator[]" << endl;
	cout << "1. empty()\t" << "check if the container is empty" << endl;
	cout << "2. size()\t" << "print the size of the container" << endl;
	cout << "3. push_back()\t" << "insert an element to the back of the container" << endl;
	cout << "4. front()\t" << "print the element at the front of the container" << endl;
	cout << "5. back()\t" << "print the element at the back of the container" << endl;
	cout << "6. find()\t" <<  "find and print element by value" << endl;
	cout << "7. removeAndRetrieve()\t" << "remove element by value and print it" << endl;
	cout << "8. removeAllElements()\t" << "remove all elements from the container" << endl;
	cout << "9. removeAndDelete()\t" << "remove element and call its DTOR" << endl;
	cout << ":";
}

int readInput(int minIndex, int maxIndex){
	string input;
	int option;
	while (true){
		getline(cin,input);
		if (input == "quit"){
			QUIT_ENTERED = 1;
			return -1;
		}
		option = 0;
		option = atoi(input.c_str());
		if ((option < minIndex) || (option>maxIndex)){
			cout << "enter a valid option between 1 and " << maxIndex << endl;
			continue;
		}
		break;
	}
	return option;
}

ostream& sep(ostream& os){
	return os << "==================================" << endl << endl;
}

int main(){
	tContainer_t<string, vector> vec;
	tContainer_t<string, list> lst;
	cout << "this tester works with strings as the container elements";
	cout << "enter \"quit\" at any time to quit the program" << endl;
	while (true){

		// CHOOSE A CONTAINER
		printContainerSelection();
		int input = readInput(1,2);
		if (QUIT_ENTERED){
			exit(0);
		}
		switch(input){
		case 1: {
			C_TYPE = C_VECTOR;
			cout << "working with vector<string*>" << endl;
			break;
				}
		case 2: {
			C_TYPE = C_LIST;
			cout << "working with list<string*>" << endl;
			break;
				}
		} // end of switch

		cout << sep;

		while (true) {
			// CHOOSE AN OPERATION
			printOperationSelection();
			int input = readInput(0,9);
			if (QUIT_ENTERED){
				exit(0);
			}
			switch(input){
			case 0: {//operator[]
				string input;
				cout << "enter index: ";
				getline(cin, input);
				int index = atoi(input.c_str());
				try{
					if (C_TYPE==C_VECTOR){
						cout << *vec[index] << endl;
					}
					else {
						cout << *lst[index] << endl;
					}
				}
				catch (char *exception){
					cout << exception << endl;
				}
				cout << sep;
				break;
					}
			case 1: {//empty()
				if (C_TYPE==C_VECTOR){
					cout << (vec.empty()?"EMPTY":"NOT EMPTY") << endl;
				}
				else {
					cout << (lst.empty()?"EMPTY":"NOT EMPTY") << endl;
				}
				cout << sep;
				break;
					}
			case 2: {//size()
				if (C_TYPE==C_VECTOR){
					cout << vec.size() << endl;
				}
				else {
					cout << lst.size() << endl;
				}
				cout << sep;
				break;
				}
			case 3: {//push_back()
				string input;
				cout << "enter element to push back: ";
				getline(cin, input);
				if (C_TYPE==C_VECTOR){
					vec.push_back(new string(input));
				}
				else {
					lst.push_back(new string(input));
				}
				cout << sep;
				break;
				}
			case 4: {//front()
				cout << "element in front: ";
				if (C_TYPE==C_VECTOR){
					if (vec.empty()){
						cout << "container is empty" << endl;
					}
					else {
						string *ptr = vec.front();
						cout << *ptr << endl;
					}
				}
				else {
					if (lst.empty()){
						cout << "container is empty" << endl;
					}
					else {
						string *ptr = lst.front();
						cout << *ptr << endl;
					}
				}
				cout << sep;
				break;
				}
			case 5: {//back()
				cout << "element in back: ";
				if (C_TYPE==C_VECTOR){
					if (lst.empty()){
						cout << "container is empty" << endl;
					}
					else {
						string *ptr = vec.back();
						cout << *ptr << endl;
					}
				}
				else {
					if (lst.empty()){
						cout << "container is empty" << endl;
					}
					else {
						string *ptr = lst.back();
						cout << *ptr << endl;
					}
				}
				cout << sep;
				break;
				}
			case 6: {//finde()
				string input;
				cout << "enter element to find: ";
				getline(cin,input);

				if (C_TYPE==C_VECTOR){
					string *ptr = vec.find(input);
					if (ptr == 0) {
						cout << "element was not found in container" << endl;
					}
					else {
						cout << "found " << input << " in the container: " << *ptr << endl;
					}
				}
				else {
					string *ptr = lst.find(input);
					if (ptr == 0) {
						cout << "element was not found in container" << endl;
					}
					else {
						cout << "found " << input << " in the container: " << *ptr << endl;
					}
				}
				cout << sep;
				break;
				}
			case 7: {//removeAndRetrieve()
				string input;
				cout << "enter element to remove: ";
				getline(cin,input);
				if (C_TYPE==C_VECTOR){
					string *ptr = vec.removeAndRetrieve(input);
					if (ptr == 0){
						cout << "element is not in the container" << endl;
					}
					else {
						cout << "removed " << *ptr << " from the container" << endl;
					}
				}
				else {
					string *ptr = lst.removeAndRetrieve(input);
					if (ptr == 0){
						cout << "element is not in the container" << endl;
					}
					else {
						cout << "removed " << *ptr << " from the container" << endl;
					}
				}
				cout << sep;
				break;
				}
			case 8: {//removeAllElements()
				cout << "removing all elements" << endl;
				if (C_TYPE==C_VECTOR){
					vec.removeAllElements();
				}
				else {
					lst.removeAllElements();
				}
				cout << sep;
				break;
					}
			case 9: {//removeAndDelete()
				string input;
				cout << "enter element to remove and delete: ";
				getline(cin,input);
				if (C_TYPE==C_VECTOR){
					if (vec.removeAndDelete(input)){
						cout << "OK" << endl;
					}
					else {
						cout << "failed" << endl;
					}
				}
				else {
					if (lst.removeAndDelete(input)){
						cout << "OK" << endl;
					}
					else {
						cout << "failed" << endl;
					}
				}
				cout << sep;
				break;
					}
			} // end of switch

		}// end of inner while (true)
	
	} // end of outter while(true)

	// delete any allocation made
	for (unsigned int i =0; i< vec.size();i++){
		delete vec[i];
	}
	for (unsigned int i =0; i< lst.size();i++){
		delete lst[i];
	}
} // end of main

 
